#include <stdio.h>
#include "modbus-tcp.h"
#include "modbus.h"
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/msg.h>
#include <stdbool.h>
#include "msg_queue_peer.h"
#include "pub_define.h"
#include "shmem.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <strings.h>

union mval
{
    int data_switch;
    int data_val_i;
    double data_val_f;
};

struct mdata
{
    int data_key;           // 数据编号
    char data_name[50];     // 数据名称
    int data_type;  // 数据类型
    union mval val;
};

struct STM32
{
    struct mdata data[14];
};

struct Modbus
{
    struct mdata data[6];
};

//共享内存结构体
struct CJSON
{
    char version[50];      // 版本
    int report_type;   // 报告类型
    int report_period; // 报告周期

    char mqtt_server_addr[50]; // mqtt服务器ip
    int mqtt_server_port;  // mqtt服务器端口号

    char mb_dev_addr[50]; // modbus端ip
    int mb_dev_port;  // modbus端口号

    // STM32
    struct STM32 stm32;

    // modbus
    struct Modbus modbus;
};

//消息结构体
struct mtext
{
    int data_Humidifier;        // 加湿器阈值
    int data_Dehumidifier;      // 除湿器阈值
    int data_TemController;     // 控温仪器阈值
    int Tmp_Hign;               // 温度制冷阈值
    int Tmp_Low;                // 温度制热阈值
    int Hum;                    // 除湿阈值
    int mode;                   // 工作模式(除湿/控温)
    bool mode_aircondition;     // 空调开关状态
    bool state_Humidifier;      // 加湿器工作状态
    bool state_Dehumidifier;    // 除湿器工作状态
    bool state_TemController;   // 控温仪器工作状态
};

//消息队列结构体
struct msgQueue
{
    int key;                   // 对应点表中的key值
    struct mtext text;
    
};

//STM32结构体
typedef struct STM32Data
{
    int Tmp_Hign;             // 温度制冷阈值
    int Tmp_Low;              // 温度制热阈值
    int Hum;                  // 除湿阈值
    int mode;                 // 工作模式(除湿/控温)
    float data_Vol;           // 电压值
    float data_Tmp;           // sht20温度
    float data_Hum;           // sht20湿度
    float data_Somke;         // 烟雾传感器
    bool mode_aircondition;    //空调开关状态
    bool state_Fire;           // 火焰传感器
    bool state_Beep;           // 蜂鸣器开关
    bool state_Fan;            // 风扇开关
    bool state_RefrChip;       // 空调制冷片工作状态
    bool state_HeatElement;    // 空调制预热工作状态
}Data_32;

struct shm_param para; //共享内存结构体
struct CJSON jsonRejion ;//共享内存对应结构体
struct msgQueue QueueRejion;//消息队列结构体

#define ERR_MSG(msg)                           \
    do                                         \
    {                                          \
        fprintf(stderr, "line:%d ", __LINE__); \
        perror(msg);                           \
    } while (0)

int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("请输入：<port>\n");
        return -1;
    }


    //共享内存初始化
    if(shm_init(&para, "shmMery", sizeof(jsonRejion)) == -1)
    {
        ERR_MSG("开辟共享内存失败");
        return -1;
    }
    //映射
    struct CJSON *json = NULL;
    json = shm_getaddr(&para);
    if(json == (struct CJSON *)-1)
    {
        ERR_MSG("映射失败");
        return -1;
    }

    int acceptfd, sockfd;
    // 1.创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    // printf("%d\n", sockfd);

    // 2.bind绑定ip和port
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    saddr.sin_addr.s_addr = INADDR_ANY;
    socklen_t addrlen = sizeof(saddr);
    if (bind(sockfd, (struct sockaddr *)&saddr, addrlen) < 0)
    {
        ERR_MSG("bind");
        return -1;
    }

    // 3.监听,listen将主动套接字变被动套接字
    if (listen(sockfd, 6) < 0)
    {
        ERR_MSG("listen");
        return -1;
    }

    Data_32 data32;

    fd_set readfds, tempfds;
    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);
    FD_SET(0, &readfds);
    int i, max = 3;
    while (1)
    {
        tempfds = readfds;
        if (select(max + 1, &tempfds, NULL, NULL, NULL) < 0)
        {
            ERR_MSG("select");
            close(sockfd);
            return -1;
        }

        if (FD_ISSET(sockfd, &tempfds))
        {
            // 4.3.accept阻塞等待连接可以建立，有的话就解除阻塞建立连接，并产生一个新的套接字
            acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &addrlen);
            if (acceptfd < 0)
            {
                ERR_MSG("accept");
                close(sockfd);
                return -1;
            }
            FD_SET(acceptfd, &readfds);
            if (max < acceptfd)
                max = acceptfd;
            printf("%d ip:%s port:%d\n", acceptfd, inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
        }
        // 发送
        if (FD_ISSET(0, &tempfds))
        {
            // 下发
            for (i = 4; i <= max; i++)
            {
                if (FD_ISSET(i, &readfds))
                {
                    if(msg_queue_msgexist("msgqueue", 100))
                    {
                        msg_queue_recv("msgqueue", &QueueRejion, sizeof(QueueRejion),1 , 0);
                        
                }
            }
        }
        // 接收
        for (i = 4; i <= max; i++)
        {
            if (FD_ISSET(i, &tempfds))
            {
                int rv = recv(i, &data32, sizeof(data32), 0);
                if (rv < 0)
                {
                    ERR_MSG("data32ecv");
                    close(sockfd);
                    return -1;
                }
                else if (rv == 0)
                {
                    printf("%d quit\n", i);
                    FD_CLR(i, &readfds);
                    while (!FD_ISSET(max, &readfds))
                        max -= 1;
                    close(i);
                }
                else
                {
                    //接收
                    //printf("湿度：%f 温度：%f 火焰：%d\n", data32.data_Hum, data32.data_Tmp, data32.stata_Fire);
                    json->stm32.data[0].val.data_val_i = data32.Tmp_Hign;
                    json->stm32.data[1].val.data_val_i = data32.Tmp_Low;
                    json->stm32.data[2].val.data_val_i = data32.Hum;
                    json->stm32.data[3].val.data_val_i = data32.mode;
                    json->stm32.data[4].val.data_val_f = data32.data_Vol;
                    json->stm32.data[5].val.data_val_f = data32.data_Tmp;
                    json->stm32.data[6].val.data_val_f = data32.data_Hum;
                    json->stm32.data[7].val.data_val_f = data32.data_Somke;
                    json->stm32.data[8].val.data_switch = data32.mode_aircondition;
                    json->stm32.data[9].val.data_switch = data32.state_Fire;
                    json->stm32.data[10].val.data_switch = data32.state_Beep;
                    json->stm32.data[11].val.data_switch = data32.state_Fan;
                    json->stm32.data[12].val.data_switch = data32.state_RefrChip;
                    json->stm32.data[13].val.data_switch = data32.state_HeatElement;
                }
            }
        }
    }
    close(sockfd);
    return 0;
}
